#ifndef MODULES_MAP_HDMAP_ADAPTER_ODR_PARSER_HEADER_DATA_DEFINE_H_
#define MODULES_MAP_HDMAP_ADAPTER_ODR_PARSER_HEADER_DATA_DEFINE_H_

#include "modules/map/proto/map.pb.h"

#include <string>
#include <vector>
#include <map>

namespace apollo {
namespace hdmap {
namespace adapter {

enum PredecessorType {
    JUNCTION,
    ROAD
};

enum ContactPointType {
    START,
    END
};

enum ESpeedUnitType {
   KM_PER_H,
   M_PER_S,
   MILE_PER_H
};

struct Predecessor {
    PredecessorType elementType;
    std::string elementId;
    ContactPointType contactPoint;
};

struct Link {
    Predecessor* predecessor;
    Predecessor* successor;
    //std::vector<> neighbor;
};

enum HdrGeometryType {
    GEO_LINE,
    GEO_ARC,
    GEO_SPIRAL,
    GEO_PARAPOLY3
};

struct ParaPoly3 {
    double aU, bU, cU, dU;
    double aV, bV, cV, dV;
};

struct Geometry {
    double s;
    double x;
    double y;
    double hdg;
    double length;

    HdrGeometryType type;
    ParaPoly3 poly3;
    double arc_curvature;  // only used if type is arc
    double spiral_curve_start; // only used if type is spiral
    double spiral_curve_end;   // only used if type is spiral
};

struct PlanView {
    std::vector<Geometry*> geometrys;
};

enum LaneType {
    NONE,
    DRIVING,
    SIDEwALK
};

struct LaneWidth {
    double sOffset;
    double a;
    double b;
    double c;
    double d;
};

enum RoadMarkType {
    ROADMARK_NONE,
    ROADMARK_BROKEN,
    ROADMARK_SOLID,
    ROADMARK_SOLID_SOLID,
    ROADMARK_SOLID_BROKEN,
    ROADMARK_BROKEN_SOLID,
    ROADMARK_BROKEN_BROKEN,
    ROADMARK_BOTTS_DOTS,
    ROADMARK_GRASS,
    ROADMARK_CURB
};

enum RoadMarkColor {
    ROADMARK_STANDARD,
    ROADMARK_BLUE,
    ROADMARK_RED,
    ROADMARK_GREEN,
    ROADMARK_WHITE,
    ROADMARK_YELLOW
};

struct LaneRoadMark {
    double sOffset;
    RoadMarkType type;
    double width;
    // weight
    // color
    RoadMarkColor color; // standard - white; blue;
                       // green, red, white, yellow
    std::string laneChange;
};

struct TmpLaneConnection {
    std::string roadId;
    std::string laneId;
    std::string laneUid;
};

struct Lane {
    std::string uid;
    std::string id;
    LaneType type;
    bool level;

    Link link;

    std::vector<LaneWidth> widths;
    std::vector<LaneWidth> borders;
    std::vector<LaneRoadMark> roadMarks;
    double speedOffset;
    double speedMax;
    ESpeedUnitType speedUnit;
	
	int left_boundary; // TODO
	int rightt_boundary; // TODO

    std::vector<TmpLaneConnection> predecessors;
    std::vector<TmpLaneConnection> successors;
};

struct LaneSection {
    double s; // start offset of the section
    double e; // end offset of the section, for last section, -1 is given

    Lane* center;
    std::vector<Lane*> right;
    std::vector<Lane*> left;
	
	int boundary; // TODO
};

enum ERoadType {
    ROADTYPE_UNKNOWN,
    ROADTYPE_RURAL,
    ROADTYPE_MOTORWAY,
    ROADTYPE_TOWN,
    ROADTYPE_LOWSPEED,
    ROADTYPE_PEDESTRIAN,
    ROADTYPE_BICYCLE
};

struct RoadType {
    double s;
    ERoadType type;

    double maxSpeed; // 0 if not specified, unit: m/s   
};

struct Elevation {
    double s;
    double a;
    double b;
    double c;
    double d;
};

struct LateralProfile {
    std::vector<Elevation> superelevations;
    std::vector<Elevation> crossfalls;
};

struct CornerLocal {
    double u;
    double v;
    double z;
    double height;
};

struct CornerRoad {
    double s;
    double t;
    double dz;
    double height;
};

struct ObjectOutline {
    std::vector<CornerLocal> cornerLocals;
    std::vector<CornerRoad> cornerRoads;
};

enum RoadObjectType {
  ROAD_STOPLINE,
  ROAD_CROSSWALK
};

struct RoadObject {
    RoadObjectType type;
    std::string name;
    std::string id;
    double s;
    double t;
    double zOffset;
    double validLength;
    std::string orientation;
    double length;
    double width;
    double radius;
    double height;
    double hdg;
    double pitch;
    double roll;

    std::vector<ObjectOutline> outlines;
};

enum RoadSignalType {
    ROAD_TRAFFICLIGHT
};

struct UserData {
  std::vector<std::pair<std::string, std::string>> tags;
  // subsignal element key: id, value: type
  std::vector<std::string> subSignalIds;
  std::vector<std::string> subSignalTypes;
};

struct RoadSignal {
    RoadSignalType type;
    std::string id;
    std::string name;
    std::string orientation;
    double s;
    double t;
    double zOffset;
    std::string country;
    std::string subtype;
    double value;
    std::string unit;
    double height;
    double width;
    std::string text;
    double hOffset;
    double pitch;
    double roll;

    UserData userData;
};

struct Road {
    std::string name;
    double length;
    std::string id;
    std::string junction_id;

    RoadType* type;
    Link link;
    PlanView planView;
    std::vector<LaneSection*> laneSections;
    std::vector<Elevation> elevationProfile;
    LateralProfile* lateralProfile;

    std::vector<RoadObject> objects;
    std::vector<RoadSignal> signals;
};

//////////////////////////////////////////////

struct Connection {
    std::string id;
    std::string incomingRoad;
    std::string connectingRoad;
    ContactPointType contactPoint;

    std::vector<std::string> laneLinkFroms;
    std::vector<std::string> laneLinkTos;
};

struct Junction {
    std::string name;
    std::string id;
    std::vector<Connection*> connections;
};

struct OdrMap {
    // key is road id
    std::map<std::string, Road*> roads;
    // key is junction id
    std::map<std::string, Junction*> junctions;
};

}  // namespace adapter
}  // namespace hdmap
}  // namespace apollo

#endif